package com.jumi.microservice.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jumi.microservice.common.context.SpringApplicationContext;
import com.jumi.microservice.constant.ExceptionEnum;
import com.jumi.microservice.constant.NumberConstant;
import com.jumi.microservice.constant.StatusEnum;
import com.jumi.microservice.domain.Priority;
import com.jumi.microservice.domain.Role;
import com.jumi.microservice.domain.RolePriorityRelationship;
import com.jumi.microservice.domain.dto.PriorityDTO;
import com.jumi.microservice.domain.temp.PriorityTemp;
import com.jumi.microservice.domain.vo.PriorityVO;
import com.jumi.microservice.mapper.PriorityMapper;
import com.jumi.microservice.mapper.RoleMapper;
import com.jumi.microservice.mapper.RolePriorityRelationshipMapper;
import com.jumi.microservice.service.PriorityService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 权限表 服务实现类
 * </p>
 *
 * @author liuz
 * @since 2020-07-18
 */
@Service
@Transactional
public class PriorityServiceImpl extends ServiceImpl<PriorityMapper, Priority> implements PriorityService {

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private RolePriorityRelationshipMapper rolePriorityRelationshipMapper;

    /**
     * spring容器组件
     */
    @Autowired
    private SpringApplicationContext context;

    /**
     * 新增菜单
     * @param dto 菜单信息
     */
    @Override
    public void insert(PriorityDTO dto) {
        Priority p = dto2Po(dto);
        ExceptionEnum.FAIL_NULL.doThrowIf(p==null);
        //判断权限标识唯一
        int count = baseMapper.selectCount(
                Wrappers.<Priority>lambdaQuery()
                        .eq(Priority::getPriorityCode,p.getPriorityCode()));
        ExceptionEnum.FAIL_MENU_EXIST.doThrowIf(count>NumberConstant.NUMBER_ZERO);
        p.setCreateTime(LocalDateTime.now());
        p.setUpdateTime(LocalDateTime.now());
        baseMapper.insert(p);
    }

    /**
     * 编辑菜单
     * @param dto 菜单信息
     */
    @Override
    public void update(PriorityDTO dto) {
        Priority p = dto2Po(dto);
        ExceptionEnum.FAIL_NULL.doThrowIf(p==null);
        //判断权限标识唯一
        int count = baseMapper.selectCount(
                Wrappers.<Priority>lambdaQuery()
                        .eq(Priority::getPriorityCode,p.getPriorityCode())
                        .ne(Priority::getId,p.getId())
        );
        ExceptionEnum.FAIL_MENU_EXIST.doThrowIf(count>NumberConstant.NUMBER_ZERO);
        p.setUpdateTime(LocalDateTime.now());
        baseMapper.updateById(p);
    }

    /**
     * 删除菜单
     * @param id 主键id
     * @param username 用户名
     */
    @Override
    public void delete(Long id, String username) {
        ExceptionEnum.FAIL_ID_NULL.doThrowIf(id==null);
        //校验
        Priority p = baseMapper.selectById(id);
        //是否启用状态
        ExceptionEnum.FAIL_STATUS.doThrowIf(p.getStatus()== StatusEnum.STATUS_YES.getCode());
        //是否存在未删除子菜单
        List<PriorityTemp> temps = baseMapper.selectChildren(id);
        ExceptionEnum.FAIL_HAS_CHILD.doThrowIf(temps.size()>NumberConstant.NUMBER_ZERO);
        //判断是否已绑定角色
        int count = roleMapper.selectCount(
                Wrappers.<Role>lambdaQuery()
                        .eq(Role::getIsDel,StatusEnum.STATUS_NO.getCode())
                        .apply("id in (select role_id from auth_role_priority_relationship where priority_id = "+id+" )"));
        ExceptionEnum.FAIL_HAS_ROLE.doThrowIf(count>NumberConstant.NUMBER_ZERO);
        p.setIsDel(StatusEnum.STATUS_YES.getCode());
        p.setUpdateTime(LocalDateTime.now());
        p.setModifier(username);
        baseMapper.updateById(p);
    }

    /**
     * 菜单详情
     * @param id 主键id
     * @return
     */
    @Override
    public PriorityDTO selectById(Long id) {
        ExceptionEnum.FAIL_ID_NULL.doThrowIf(id==null);
        Priority p = baseMapper.selectById(id);
        return po2Dto(p);
    }

    /**
     * 菜单启用/停用
     * @param id 主键id
     * @param status 状态
     */
    @Override
    public void enabledStatus(Long id, Integer status) {
        ExceptionEnum.FAIL_ID_NULL.doThrowIf(id==null);
        Priority p = baseMapper.selectById(id);
        ExceptionEnum.FAIL_NULL.doThrowIf(p==null);
        p.setStatus(status);
        p.setUpdateTime(LocalDateTime.now());
        //暂时写死
        p.setModifier("admin");
        baseMapper.updateById(p);
    }

    /**
     * 根据角色id获取权限
     * @param roleId 角色id
     * @return
     */
    @Override
    public List<PriorityVO> selectPriorsByRoleId(Long roleId) {
        //先获取根目录
        List<Priority> list = baseMapper.selectList(
                Wrappers.<Priority>lambdaQuery()
                        .eq(Priority::getIsDel,StatusEnum.STATUS_NO.getCode())
                        .eq(Priority::getParentId, NumberConstant.NUMBER_ZERO));
        //获取子菜单
        List<PriorityVO> vos = list.stream().map(po -> {
            PriorityVO vo = po2Vo(po);
            getChildren(vo);
            return vo;
        }).collect(Collectors.toList());
        return vos;
    }

    /**
     * 根据登录用户获取菜单
     * @param accountId 用户id
     * @param isSuper 超级管理员
     * @return
     */
    @Override
    public List<Priority> authorizeList(Long accountId, boolean isSuper) {
        //根据用户角色权限绑定关系获取权限id
        List<Priority> priorities = null;
        if(isSuper){
            priorities = baseMapper.selectList(Wrappers.lambdaQuery());
        }else{
            priorities = baseMapper.authorizeList(accountId);
        }
        return priorities;
    }

    /**
     * 对象转换 dto->do
     * @param dto
     * @return
     */
    private Priority dto2Po(PriorityDTO dto){
        Priority r = null;
        try {
            r = dto.clone(Priority.class);
        }catch (Exception e){
            ExceptionEnum.FAIL_CHANGE.newException();
        }
        return r;
    }

    /**
     * 对象转换 po->dto
     * @param po
     * @return
     */
    private PriorityDTO po2Dto(Priority po){
        PriorityDTO r = null;
        try {
            r = po.clone(PriorityDTO.class);
        }catch (Exception e){
            ExceptionEnum.FAIL_CHANGE.newException();
        }
        return r;
    }

    /**
     * 根据父菜单获取子菜单
     * @param vo
     */
    private void getChildren(PriorityVO vo){
        //获取当前的子菜单
       List<Priority> list = baseMapper.selectList(
               Wrappers.<Priority>lambdaQuery()
                       .eq(Priority::getParentId,vo.getId())
                       .eq(Priority::getStatus,StatusEnum.STATUS_YES.getCode()));
       List<PriorityVO> vos = list.stream().map(p->{
           PriorityVO vop = po2Vo(p);
           getChildren(vop);
           return vop;
       }).collect(Collectors.toList());
       vo.setChildren(vos);
    }

    /**
     * po->vo
     * @param p
     * @return
     */
    private PriorityVO po2Vo(Priority p){
        PriorityVO vo = null;{
            try {
                vo = p.clone(PriorityVO.class);
            }catch (Exception e){
                ExceptionEnum.FAIL_CHANGE.newException();
            }
        }
        return vo;
    }
}
